package com.q3d.demo.svc.gateway.exception;

import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.q3d.demo.common.lib.service.response.ResponseBase;
import com.q3d.demo.common.lib.service.response.ResponseStatus;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

@Slf4j
@Component
@RequiredArgsConstructor
/**
 * 网关的全局异常拦截器
 * 
 * @author 叶湘 ( weixin:yexiang841, email:yexiang841@qq.com )
 */
public class GatewayExceptionHandler implements ErrorWebExceptionHandler, Ordered {

    /**
     * 离 0 越远越早执行，必须 < -1，否则不会执行获取后端响应的逻辑
     * 
     * @return int
     */
    @Override
    public int getOrder() {
        return -19;
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        // 1、获取响应对象
        ServerHttpResponse response = exchange.getResponse();
        // 2、response 是否结束，用于多个异常处理时候
        if (response.isCommitted()) {
            return Mono.error(ex);
        }
        // 3、统一设置为 JSON 格式响应
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        // 4、设置响应内容
        return response
                .writeWith(Mono.fromSupplier(() -> {
                    DataBufferFactory bufferFactory = response.bufferFactory();
                    ResponseBase<?> responseBody = ResponseBase
                            .builder()
                            .code(ResponseStatus.SERVICE_UNAVAILABLE.getCode())
                            .answer(ResponseStatus.SERVICE_UNAVAILABLE.getAnswer())
                            .message(ex.getMessage())
                            .build();
                    ObjectMapper objectMapper = new ObjectMapper();
                    String responseJson = JSON.toJSONString(responseBody);
                    log.warn("response: {}", responseJson);
                    try {
                        // 设置响应到 Response 的数据
                        return bufferFactory.wrap(objectMapper.writeValueAsBytes(responseBody));
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                        return null;
                    }
                }));
    }
}
